using System;
using Xunit;
using static SmartSite.Frame.FrameTypeEnum;

namespace SmartSite.Frame.Test
{
    public class TestBaseFrame
    {
        [Fact]
        public void TestSizeAndPositing()
        {
            BaseFrame frame = new BaseFrame();

            Assert.Equal(5, frame.Buffer.Count);
            Assert.Equal(0, (int)frame.ProtocolVersion.Index);
            Assert.Equal(4, (int)frame.ProtocolVersion.Count);
            Assert.Equal(4, (int)frame.FactoryCode.Index);
            Assert.Equal(4, (int)frame.FactoryCode.Count);
            Assert.Equal(8, (int)frame.FrameType.Index);
            Assert.Equal(5, (int)frame.FrameType.Count);
            Assert.Equal(13, (int)frame.InfoLength.Index);
            Assert.Equal(11, (int)frame.InfoLength.Count);
            Assert.Equal(24, (int)frame.CRC.Index);
            Assert.Equal(16, (int)frame.CRC.Count);
        }

        [Fact]
        public void TestDefaultValue()
        {
            BaseFrame frame = new BaseFrame();

            Assert.Equal(4, frame.ProtocolVersion.Value);
            Assert.Equal(4, frame.FactoryCode.Value);
            Assert.Equal("0x44", $"0x{frame.Buffer[0]:X2}");
            Assert.Equal(NullFrameType, frame.FrameType.Value);
            Assert.Equal(0, frame.InfoLength.Value);
            Assert.Equal(0, frame.CRC.Value);
            // UInt16 CRCValue = CrcField.CalculationCRC(Buffer, 0, CRC.IntField.Field.Index);
            // Assert.Equal("0x130", $"0x{CRCValue:X2}");
            // CRC.Value = CRCValue;
            // Assert.Equal("0x130", $"0x{CRC.Value:X2}");
            // CRCValue = CrcField.CalculationCRC(Buffer, 0, CRC.IntField.Field.Index);
            // Assert.Equal("0x130", $"0x{CRCValue:X2}");
        }

        [Fact]
        void TestProtocolVersion()
        {
            BaseFrame frame = new BaseFrame();

            frame.ProtocolVersion.Value = 0x0F;
            frame.FactoryCode.Value = 0x4;
            Assert.Equal(5, frame.Buffer.Count);
            Assert.Equal("0x0F", $"0x{frame.ProtocolVersion.Value:X2}");
            Assert.Equal(4, frame.FactoryCode.Value);
            Assert.Equal(NullFrameType, frame.FrameType.Value);
            Assert.Equal(0, frame.InfoLength.Value);

            // Assert.Equal("0x130", $"0x{CRC.Value:X2}");
            // Assert.Equal("0x3230", $"0x{CrcField.CalculationCRC(Buffer, 0, CRC.IntField.Field.Index):X2}");

            Assert.Throws<ArgumentOutOfRangeException>(() => frame.ProtocolVersion.Value = 0x10);
        }

        [Fact]
        void TestFactoryCode()
        {
            BaseFrame frame = new BaseFrame();

            frame.FactoryCode.Value = 0;
            Assert.Equal(0, frame.FactoryCode.Value);
            Assert.Equal(5, frame.Buffer.Count);
            Assert.Equal(4, frame.ProtocolVersion.Value);
            Assert.Equal(0, frame.FactoryCode.Value);
            Assert.Equal(NullFrameType, frame.FrameType.Value);
            Assert.Equal(0, frame.InfoLength.Value);

            frame.FactoryCode.Value = 0xF;
            Assert.Equal(5, frame.Buffer.Count);
            Assert.Equal(4, frame.ProtocolVersion.Value);
            Assert.Equal(0xF, frame.FactoryCode.Value);
            Assert.Equal(NullFrameType, frame.FrameType.Value);
            Assert.Equal(0, frame.InfoLength.Value);

            Assert.Throws<ArgumentOutOfRangeException>(() => { frame.FactoryCode.Value = 0x10; });
        }

        [Fact]
        void TestFrameType()
        {
            BaseFrame frame = new BaseFrame();

            Assert.Equal(NullFrameType, frame.FrameType.Value);

            frame.FrameType.Value = NullFrameType;
            Assert.Equal(4, frame.ProtocolVersion.Value);
            Assert.Equal(4, frame.FactoryCode.Value);
            Assert.Equal(NullFrameType, frame.FrameType.Value);
            Assert.Equal(0, frame.InfoLength.Value);

            frame.FrameType.Value = (FrameTypeEnum)0x1F;
            Assert.Equal(4, frame.ProtocolVersion.Value);
            Assert.Equal(4, frame.FactoryCode.Value);
            Assert.Equal((FrameTypeEnum)0x1F, frame.FrameType.Value);
            Assert.Equal(0, frame.InfoLength.Value);

            Assert.Throws<ArgumentOutOfRangeException>(() => frame.FrameType.Value = (FrameTypeEnum)0x20);
            Assert.Throws<ArgumentOutOfRangeException>(() => frame.FrameType.Value = (FrameTypeEnum)(-1));
        }

        [Fact]
        void TestInfoLength()
        {
            BaseFrame frame = new BaseFrame();

            Assert.Equal(0, frame.InfoLength.Value);

            frame.InfoLength.Value = 0x7FF;
            Assert.Equal(4, frame.ProtocolVersion.Value);
            Assert.Equal(4, frame.FactoryCode.Value);
            Assert.Equal("0x44", $"0x{frame.Buffer[0]:X2}");
            Assert.Equal(NullFrameType, frame.FrameType.Value);
            Assert.Equal(0, frame.CRC.Value);

            Assert.Equal(0x7FF, frame.InfoLength.Value);

            frame.InfoLength.Value = 0;
            Assert.Equal(4, frame.ProtocolVersion.Value);
            Assert.Equal(4, frame.FactoryCode.Value);
            Assert.Equal("0x44", $"0x{frame.Buffer[0]:X2}");
            Assert.Equal(NullFrameType, frame.FrameType.Value);
            Assert.Equal(0, frame.CRC.Value);

            Assert.Equal(0, frame.InfoLength.Value);

            Assert.Throws<ArgumentOutOfRangeException>(() => frame.InfoLength.Value = 0x800);
        }

        [Fact]
        void TestCRC()
        {
            BaseFrame frame = new BaseFrame();

            // Assert.Equal(0x130, CRC.Value);
            frame.CRC.Value = 0xFFFF;
            Assert.Equal(4, frame.ProtocolVersion.Value);
            Assert.Equal(4, frame.FactoryCode.Value);
            Assert.Equal("0x44", $"0x{frame.Buffer[0]:X2}");
            Assert.Equal(NullFrameType, frame.FrameType.Value);
            Assert.Equal(0, frame.InfoLength.Value);
            Assert.Equal(0xFFFF, frame.CRC.Value);

            frame.CRC.Value = 0;
            Assert.Equal(4, frame.ProtocolVersion.Value);
            Assert.Equal(4, frame.FactoryCode.Value);
            Assert.Equal("0x44", $"0x{frame.Buffer[0]:X2}");
            Assert.Equal(NullFrameType, frame.FrameType.Value);
            Assert.Equal(0, frame.InfoLength.Value);
            Assert.Equal(0, frame.CRC.Value);
        }
    }
}
